/**
 * EasyUI for jQuery 1.5.5.4
 *
 * Copyright (c) 2009-2018 www.jeasyui.com. All rights reserved.
 *
 * Licensed under the freeware license: http://www.jeasyui.com/license_freeware.php
 * To use it on other terms please contact us: info@jeasyui.com
 *
 */
/**
 * form - EasyUI for jQuery
 *
 */
(function ($) {
    /**
     * submit the form
     */
    function ajaxSubmit(target, options) {
        var opts = $.data(target, 'form').options;
        $.extend(opts, options || {});

        var param = $.extend({}, opts.queryParams);
        if (opts.onSubmit.call(target, param) == false) {
            return;
        }

        // $(target).find('.textbox-text:focus').blur();
        var input = $(target).find('.textbox-text:focus');
        input.triggerHandler('blur');
        input.focus();

        var disabledFields = null;	// the fields to be disabled
        if (opts.dirty) {
            var ff = [];	// all the dirty fields
            $.map(opts.dirtyFields, function (f) {
                if ($(f).hasClass('textbox-f')) {
                    $(f).next().find('.textbox-value').each(function () {
                        ff.push(this);
                    });
                } else {
                    ff.push(f);
                }
            });
            disabledFields = $(target).find('input[name]:enabled,textarea[name]:enabled,select[name]:enabled').filter(function () {
                return $.inArray(this, ff) == -1;
            });
            disabledFields.attr('disabled', 'disabled');
        }

        if (opts.ajax) {
            if (opts.iframe) {
                submitIframe(target, param);
            } else {
                if (window.FormData !== undefined) {
                    submitXhr(target, param);
                } else {
                    submitIframe(target, param);
                }
            }
        } else {
            $(target).submit();
        }

        if (opts.dirty) {
            disabledFields.removeAttr('disabled');
        }
    }

    function submitIframe(target, param) {
        var opts = $.data(target, 'form').options;
        var frameId = 'easyui_frame_' + (new Date().getTime());
        var frame = $('<iframe id=' + frameId + ' name=' + frameId + '></iframe>').appendTo('body')
        frame.attr('src', window.ActiveXObject ? 'javascript:false' : 'about:blank');
        frame.css({
            position: 'absolute',
            top: -1000,
            left: -1000
        });
        frame.bind('load', cb);

        submit(param);

        function submit(param) {
            var form = $(target);
            if (opts.url) {
                form.attr('action', opts.url);
            }
            var t = form.attr('target'), a = form.attr('action');
            form.attr('target', frameId);
            var paramFields = $();
            try {
                for (var n in param) {
                    var field = $('<input type="hidden" name="' + n + '">').val(param[n]).appendTo(form);
                    paramFields = paramFields.add(field);
                }
                checkState();
                form[0].submit();
            } finally {
                form.attr('action', a);
                t ? form.attr('target', t) : form.removeAttr('target');
                paramFields.remove();
            }
        }

        function checkState() {
            var f = $('#' + frameId);
            if (!f.length) {
                return
            }
            try {
                var s = f.contents()[0].readyState;
                if (s && s.toLowerCase() == 'uninitialized') {
                    setTimeout(checkState, 100);
                }
            } catch (e) {
                cb();
            }
        }

        var checkCount = 10;

        function cb() {
            var f = $('#' + frameId);
            if (!f.length) {
                return
            }
            f.unbind();
            var data = '';
            try {
                var body = f.contents().find('body');
                data = body.html();
                if (data == '') {
                    if (--checkCount) {
                        setTimeout(cb, 100);
                        return;
                    }
                }
                var ta = body.find('>textarea');
                if (ta.length) {
                    data = ta.val();
                } else {
                    var pre = body.find('>pre');
                    if (pre.length) {
                        data = pre.html();
                    }
                }
            } catch (e) {
            }
            opts.success.call(target, data);
            setTimeout(function () {
                f.unbind();
                f.remove();
            }, 100);
        }
    }

    function submitXhr(target, param) {
        var opts = $.data(target, 'form').options;
        var formData = new FormData($(target)[0]);
        for (var name in param) {
            formData.append(name, param[name]);
        }
        $.ajax({
            url: opts.url,
            type: 'post',
            xhr: function () {
                var xhr = $.ajaxSettings.xhr();
                if (xhr.upload) {
                    xhr.upload.addEventListener('progress', function (e) {
                        if (e.lengthComputable) {
                            var total = e.total;
                            var position = e.loaded || e.position;
                            var percent = Math.ceil(position * 100 / total);
                            opts.onProgress.call(target, percent);
                        }
                    }, false);
                }
                return xhr;
            },
            data: formData,
            dataType: 'html',
            cache: false,
            contentType: false,
            processData: false,
            complete: function (res) {
                opts.success.call(target, res.responseText);
            }
        });
    }


    /**
     * load form data
     * if data is a URL string type load from remote site,
     * otherwise load from local data object.
     */
    function load(target, data) {
        var opts = $.data(target, 'form').options;

        if (typeof data == 'string') {
            var param = {};
            if (opts.onBeforeLoad.call(target, param) == false) return;

            $.ajax({
                url: data,
                data: param,
                dataType: 'json',
                success: function (data) {
                    _load(data);
                },
                error: function () {
                    opts.onLoadError.apply(target, arguments);
                }
            });
        } else {
            _load(data);
        }

        function _load(data) {
            var form = $(target);
            for (var name in data) {
                var val = data[name];
                if (!_checkField(name, val)) {
                    if (!_loadBox(name, val)) {
                        form.find('input[name="' + name + '"]').val(val);
                        form.find('textarea[name="' + name + '"]').val(val);
                        form.find('select[name="' + name + '"]').val(val);
                    }
                }
            }
            opts.onLoadSuccess.call(target, data);
            form.form('validate');
        }

        /**
         * check the checkbox and radio fields
         */
        function _checkField(name, val) {
            var cc = $(target).find('[switchbuttonName="' + name + '"]');
            if (cc.length) {
                cc.switchbutton('uncheck');
                cc.each(function () {
                    if (_isChecked($(this).switchbutton('options').value, val)) {
                        $(this).switchbutton('check');
                    }
                });
                return true;
            }
            cc = $(target).find('input[name="' + name + '"][type=radio], input[name="' + name + '"][type=checkbox]');
            if (cc.length) {
                cc._propAttr('checked', false);
                cc.each(function () {
                    if (_isChecked($(this).val(), val)) {
                        $(this)._propAttr('checked', true);
                    }
                });
                return true;
            }
            return false;
        }

        function _isChecked(v, val) {
            if (v == String(val) || $.inArray(v, $.isArray(val) ? val : [val]) >= 0) {
                return true;
            } else {
                return false;
            }
        }

        function _loadBox(name, val) {
            var field = $(target).find('[textboxName="' + name + '"],[sliderName="' + name + '"]');
            if (field.length) {
                for (var i = 0; i < opts.fieldTypes.length; i++) {
                    var type = opts.fieldTypes[i];
                    var state = field.data(type);
                    if (state) {
                        if (state.options.multiple || state.options.range) {
                            field[type]('setValues', val);
                        } else {
                            field[type]('setValue', val);
                        }
                        return true;
                    }
                }
            }
            return false;
        }
    }

    /**
     * clear the form fields
     */
    function clear(target) {
        $('input,select,textarea', target).each(function () {
            if ($(this).hasClass('textbox-value')) {
                return;
            }
            var t = this.type, tag = this.tagName.toLowerCase();
            if (t == 'text' || t == 'hidden' || t == 'password' || tag == 'textarea') {
                this.value = '';
            } else if (t == 'file') {
                var file = $(this);
                if (!file.hasClass('textbox-value')) {
                    var newfile = file.clone().val('');
                    newfile.insertAfter(file);
                    if (file.data('validatebox')) {
                        file.validatebox('destroy');
                        newfile.validatebox();
                    } else {
                        file.remove();
                    }
                }
            } else if (t == 'checkbox' || t == 'radio') {
                this.checked = false;
            } else if (tag == 'select') {
                this.selectedIndex = -1;
            }

        });

        var tmp = $();
        var form = $(target);
        var opts = $.data(target, 'form').options;
        for (var i = 0; i < opts.fieldTypes.length; i++) {
            var type = opts.fieldTypes[i];
            var field = form.find('.' + type + '-f').not(tmp);
            if (field.length && field[type]) {
                field[type]('clear');
                tmp = tmp.add(field);
            }
        }
        form.form('validate');
    }

    function reset(target) {
        target.reset();
        var form = $(target);
        var opts = $.data(target, 'form').options;
        for (var i = opts.fieldTypes.length - 1; i >= 0; i--) {
            var type = opts.fieldTypes[i];
            var field = form.find('.' + type + '-f');
            if (field.length && field[type]) {
                field[type]('reset');
            }
        }
        form.form('validate');
    }

    /**
     * set the form to make it can submit with ajax.
     */
    function setForm(target) {
        var options = $.data(target, 'form').options;
        $(target).unbind('.form');
        if (options.ajax) {
            $(target).bind('submit.form', function () {
                setTimeout(function () {
                    ajaxSubmit(target, options);
                }, 0);
                return false;
            });
        }
        $(target).bind('_change.form', function (e, t) {
            if ($.inArray(t, options.dirtyFields) == -1) {
                options.dirtyFields.push(t);
            }
            options.onChange.call(this, t);
        }).bind('change.form', function (e) {
            var t = e.target;
            if (!$(t).hasClass('textbox-text')) {
                if ($.inArray(t, options.dirtyFields) == -1) {
                    options.dirtyFields.push(t);
                }
                options.onChange.call(this, t);
            }
        });
        setValidation(target, options.novalidate);
    }

    function initForm(target, options) {
        options = options || {};
        var state = $.data(target, 'form');
        if (state) {
            $.extend(state.options, options);
        } else {
            $.data(target, 'form', {
                options: $.extend({}, $.fn.form.defaults, $.fn.form.parseOptions(target), options)
            });
        }
    }

    function validate(target) {
        if ($.fn.validatebox) {
            var t = $(target);
            t.find('.validatebox-text:not(:disabled)').validatebox('validate');
            var invalidbox = t.find('.validatebox-invalid');
            invalidbox.filter(':not(:disabled):first').focus();
            return invalidbox.length == 0;
        }
        return true;
    }

    function setValidation(target, novalidate) {
        var opts = $.data(target, 'form').options;
        opts.novalidate = novalidate;
        $(target).find('.validatebox-text:not(:disabled)').validatebox(novalidate ? 'disableValidation' : 'enableValidation');
    }

    $.fn.form = function (options, param) {
        if (typeof options == 'string') {
            this.each(function () {
                initForm(this);
            });
            return $.fn.form.methods[options](this, param);
        }

        return this.each(function () {
            initForm(this, options);
            setForm(this);
        });
    };

    $.fn.form.methods = {
        options: function (jq) {
            return $.data(jq[0], 'form').options;
        },
        submit: function (jq, options) {
            return jq.each(function () {
                ajaxSubmit(this, options);
            });
        },
        load: function (jq, data) {
            return jq.each(function () {
                load(this, data);
            });
        },
        clear: function (jq) {
            return jq.each(function () {
                clear(this);
            });
        },
        reset: function (jq) {
            return jq.each(function () {
                reset(this);
            });
        },
        validate: function (jq) {
            return validate(jq[0]);
        },
        disableValidation: function (jq) {
            return jq.each(function () {
                setValidation(this, true);
            });
        },
        enableValidation: function (jq) {
            return jq.each(function () {
                setValidation(this, false);
            });
        },
        resetValidation: function (jq) {
            return jq.each(function () {
                $(this).find('.validatebox-text:not(:disabled)').validatebox('resetValidation');
            });
        },
        resetDirty: function (jq) {
            return jq.each(function () {
                $(this).form('options').dirtyFields = [];
            });
        }
    };

    $.fn.form.parseOptions = function (target) {
        var t = $(target);
        return $.extend({}, $.parser.parseOptions(target, [
            {ajax: 'boolean', dirty: 'boolean'}
        ]), {
            url: (t.attr('action') ? t.attr('action') : undefined)
        });
    };

    $.fn.form.defaults = {
        fieldTypes: ['tagbox', 'combobox', 'combotree', 'combogrid', 'combotreegrid', 'datetimebox', 'datebox', 'combo',
            'datetimespinner', 'timespinner', 'numberspinner', 'spinner',
            'slider', 'searchbox', 'numberbox', 'passwordbox', 'filebox', 'textbox', 'switchbutton'],
        novalidate: false,
        ajax: true,
        iframe: true,
        dirty: false,
        dirtyFields: [],
        url: null,
        queryParams: {},
        onSubmit: function (param) {
            return $(this).form('validate');
        },
        onProgress: function (percent) {
        },
        success: function (data) {
        },
        onBeforeLoad: function (param) {
        },
        onLoadSuccess: function (data) {
        },
        onLoadError: function () {
        },
        onChange: function (target) {
        }
    };
})(jQuery);
